/**
 * Excel处理工具类
 * 提供通用的Excel数据处理功能，支持多sheet页和自定义字段映射
 */
import * as XLSX from 'xlsx'

export class ExcelProcessor {
  constructor(options = {}) {
    this.options = {
      // 默认配置
      headerRowIndex: 0, // 表头行索引
      dataStartRowIndex: 1, // 数据开始行索引
      maxRows: 10000, // 最大行数限制
      encoding: 'utf8', // 编码格式
      ...options
    }
    
    // 数据校验扩展点
    this.validators = new Map()
    // 数据转换器扩展点
    this.transformers = new Map()
  }

  /**
   * 读取Excel文件
   * @param {File|ArrayBuffer} file - Excel文件或文件数据
   * @returns {Promise<Object>} 解析结果
   */
  async readExcel(file) {
    try {
      let data
      
      if (file instanceof File) {
        data = await this._fileToArrayBuffer(file)
      } else if (file instanceof ArrayBuffer) {
        data = file
      } else {
        throw new Error('不支持的文件格式')
      }

      const workbook = XLSX.read(data, { type: 'array' })
      const result = {
        sheetNames: workbook.SheetNames,
        sheets: {},
        metadata: {
          fileName: file.name || 'unknown',
          fileSize: data.byteLength,
          readTime: new Date().toISOString()
        }
      }

      // 读取所有sheet页
      for (const sheetName of workbook.SheetNames) {
        const worksheet = workbook.Sheets[sheetName]
        result.sheets[sheetName] = this._parseWorksheet(worksheet, sheetName)
      }

      return result
    } catch (error) {
      throw new Error(`Excel文件读取失败: ${error.message}`)
    }
  }

  /**
   * 根据映射配置解析数据
   * @param {Object} excelData - Excel数据
   * @param {Object} mappingConfig - 映射配置
   * @returns {Object} 解析后的数据
   */
  parseWithMapping(excelData, mappingConfig) {
    const result = {
      totalRows: 0,
      validRows: 0,
      errorRows: 0,
      sheets: {}
    }

    for (const sheetName in excelData.sheets) {
      const sheetData = excelData.sheets[sheetName]
      const mapping = mappingConfig[sheetName]
      
      if (!mapping) {
        console.warn(`未找到sheet '${sheetName}' 的映射配置`)
        continue
      }

      const parsedSheet = this._parseSheetWithMapping(sheetData, mapping, sheetName)
      result.sheets[sheetName] = parsedSheet
      result.totalRows += parsedSheet.totalRows
      result.validRows += parsedSheet.validRows
      result.errorRows += parsedSheet.errorRows
    }

    return result
  }

  /**
   * 数据预览
   * @param {Object} excelData - Excel数据
   * @param {Object} mappingConfig - 映射配置
   * @param {number} previewRows - 预览行数
   * @returns {Object} 预览数据
   */
  previewData(excelData, mappingConfig, previewRows = 10) {
    const fullResult = this.parseWithMapping(excelData, mappingConfig)
    
    // 限制预览行数
    const previewResult = { ...fullResult }
    for (const sheetName in previewResult.sheets) {
      const sheet = previewResult.sheets[sheetName]
      sheet.data = sheet.data.slice(0, previewRows)
      sheet.totalRows = Math.min(sheet.totalRows, previewRows)
    }

    return previewResult
  }

  /**
   * 生成Excel文件
   * @param {Object} data - 数据对象
   * @param {Object} templateConfig - 模板配置
   * @returns {ArrayBuffer} Excel文件数据
   */
  generateExcel(data, templateConfig) {
    const workbook = XLSX.utils.book_new()

    for (const sheetConfig of templateConfig.sheets) {
      const sheetData = data[sheetConfig.dataSource] || []
      const worksheet = this._createWorksheet(sheetData, sheetConfig)
      XLSX.utils.book_append_sheet(workbook, worksheet, sheetConfig.name)
    }

    return XLSX.write(workbook, { 
      bookType: 'xlsx', 
      type: 'array',
      bookSST: false // 优化性能
    })
  }

  /**
   * 生成模板Excel文件
   * @param {Object} templateConfig - 模板配置
   * @returns {ArrayBuffer} 模板文件数据
   */
  generateTemplate(templateConfig) {
    const workbook = XLSX.utils.book_new()

    for (const sheetConfig of templateConfig.sheets) {
      const worksheet = this._createTemplateWorksheet(sheetConfig)
      XLSX.utils.book_append_sheet(workbook, worksheet, sheetConfig.name)
    }

    return XLSX.write(workbook, { 
      bookType: 'xlsx', 
      type: 'array'
    })
  }

  /**
   * 注册数据校验器
   * @param {string} name - 校验器名称
   * @param {Function} validator - 校验函数
   */
  registerValidator(name, validator) {
    this.validators.set(name, validator)
  }

  /**
   * 注册数据转换器
   * @param {string} name - 转换器名称
   * @param {Function} transformer - 转换函数
   */
  registerTransformer(name, transformer) {
    this.transformers.set(name, transformer)
  }

  // ==================== 私有方法 ====================

  /**
   * 将File对象转换为ArrayBuffer
   * @param {File} file - 文件对象
   * @returns {Promise<ArrayBuffer>} 文件数据
   */
  _fileToArrayBuffer(file) {
    return new Promise((resolve, reject) => {
      const reader = new FileReader()
      reader.onload = (e) => resolve(e.target.result)
      reader.onerror = (e) => reject(new Error('文件读取失败'))
      reader.readAsArrayBuffer(file)
    })
  }

  /**
   * 解析工作表
   * @param {Object} worksheet - XLSX工作表对象
   * @param {string} sheetName - 工作表名称
   * @returns {Object} 解析结果
   */
  _parseWorksheet(worksheet, sheetName) {
    const range = XLSX.utils.decode_range(worksheet['!ref'] || 'A1')
    const headers = []
    const data = []

    // 提取表头
    for (let col = range.s.c; col <= range.e.c; col++) {
      const cellAddress = XLSX.utils.encode_cell({ r: this.options.headerRowIndex, c: col })
      const cell = worksheet[cellAddress]
      headers.push(cell ? String(cell.v).trim() : `Column${col + 1}`)
    }

    // 提取数据
    for (let row = this.options.dataStartRowIndex; row <= range.e.r; row++) {
      const rowData = {}
      let hasData = false

      for (let col = range.s.c; col <= range.e.c; col++) {
        const cellAddress = XLSX.utils.encode_cell({ r: row, c: col })
        const cell = worksheet[cellAddress]
        const header = headers[col]
        
        if (cell && cell.v !== undefined && cell.v !== '') {
          rowData[header] = this._convertCellValue(cell)
          hasData = true
        } else {
          rowData[header] = ''
        }
      }

      if (hasData) {
        rowData._rowIndex = row + 1 // 1-based行号
        data.push(rowData)
      }

      // 检查行数限制
      if (data.length >= this.options.maxRows) {
        console.warn(`Sheet '${sheetName}' 超过最大行数限制 ${this.options.maxRows}`)
        break
      }
    }

    return {
      name: sheetName,
      headers,
      data,
      totalRows: data.length,
      range: {
        startRow: this.options.dataStartRowIndex + 1,
        endRow: range.e.r + 1,
        startCol: range.s.c + 1,
        endCol: range.e.c + 1
      }
    }
  }

  /**
   * 根据映射配置解析工作表数据
   * @param {Object} sheetData - 工作表数据
   * @param {Array} mapping - 映射配置
   * @param {string} sheetName - 工作表名称
   * @returns {Object} 解析结果
   */
  _parseSheetWithMapping(sheetData, mapping, sheetName) {
    const result = {
      name: sheetName,
      columns: [],
      data: [],
      totalRows: sheetData.data.length,
      validRows: 0,
      errorRows: 0,
      errors: []
    }

    // 构建列配置
    const columnMap = new Map()
    for (const map of mapping) {
      if (map.targetField && map.excelColumn) {
        columnMap.set(map.excelColumn, map)
        result.columns.push({
          prop: map.targetField,
          label: map.excelColumn,
          width: 150
        })
      }
    }

    // 处理数据行
    for (const row of sheetData.data) {
      const mappedRow = {}
      const rowErrors = {}
      let hasError = false

      for (const [excelColumn, config] of columnMap) {
        const rawValue = row[excelColumn]
        
        try {
          // 数据转换
          let convertedValue = this._convertValue(rawValue, config.dataType)
          
          // 自定义转换器
          if (config.transformer && this.transformers.has(config.transformer)) {
            const transformer = this.transformers.get(config.transformer)
            convertedValue = transformer(convertedValue, row, config)
          }

          // 数据校验
          const validationResult = this._validateValue(convertedValue, config, sheetName)
          if (!validationResult.valid) {
            rowErrors[config.targetField] = validationResult.error
            hasError = true
          }

          mappedRow[config.targetField] = convertedValue
        } catch (error) {
          rowErrors[config.targetField] = error.message
          hasError = true
          mappedRow[config.targetField] = rawValue
        }
      }

      // 添加元数据
      mappedRow._rowIndex = row._rowIndex
      mappedRow._originalData = row
      if (Object.keys(rowErrors).length > 0) {
        mappedRow._errors = rowErrors
      }

      result.data.push(mappedRow)

      if (hasError) {
        result.errorRows++
        result.errors.push({
          rowIndex: row._rowIndex,
          errors: rowErrors
        })
      } else {
        result.validRows++
      }
    }

    return result
  }

  /**
   * 转换单元格值
   * @param {Object} cell - 单元格对象
   * @returns {any} 转换后的值
   */
  _convertCellValue(cell) {
    if (!cell || cell.v === undefined) return ''
    
    // 处理日期类型
    if (cell.t === 'd' || (cell.t === 'n' && XLSX.SSF.is_date(cell.z))) {
      return new Date(cell.v)
    }
    
    // 处理数字类型
    if (cell.t === 'n') {
      return cell.v
    }
    
    // 处理布尔类型
    if (cell.t === 'b') {
      return Boolean(cell.v)
    }
    
    // 默认字符串类型
    return String(cell.v).trim()
  }

  /**
   * 根据数据类型转换值
   * @param {any} value - 原始值
   * @param {string} dataType - 目标数据类型
   * @returns {any} 转换后的值
   */
  _convertValue(value, dataType) {
    if (value === '' || value === null || value === undefined) {
      return null
    }

    switch (dataType) {
      case 'string':
        return String(value).trim()
      
      case 'number':
        const num = Number(value)
        if (isNaN(num)) {
          throw new Error(`无法转换为数字: ${value}`)
        }
        return num
      
      case 'date':
        if (value instanceof Date) {
          return value.toISOString().split('T')[0]
        }
        const date = new Date(value)
        if (isNaN(date.getTime())) {
          throw new Error(`无法转换为日期: ${value}`)
        }
        return date.toISOString().split('T')[0]
      
      case 'boolean':
        if (typeof value === 'boolean') return value
        const str = String(value).toLowerCase().trim()
        if (['true', '1', 'yes', '是', '真'].includes(str)) return true
        if (['false', '0', 'no', '否', '假'].includes(str)) return false
        throw new Error(`无法转换为布尔值: ${value}`)
      
      default:
        return value
    }
  }

  /**
   * 数据校验
   * @param {any} value - 待校验的值
   * @param {Object} config - 字段配置
   * @param {string} sheetName - 工作表名称
   * @returns {Object} 校验结果
   */
  _validateValue(value, config, sheetName) {
    // 必填校验
    if (config.required && (value === null || value === undefined || value === '')) {
      return {
        valid: false,
        error: '该字段为必填项'
      }
    }

    // 正则表达式校验
    if (config.validationRule && value !== null && value !== undefined && value !== '') {
      try {
        const regex = new RegExp(config.validationRule)
        if (!regex.test(String(value))) {
          return {
            valid: false,
            error: `数据格式不符合规则: ${config.validationRule}`
          }
        }
      } catch (error) {
        console.warn(`正则表达式格式错误: ${config.validationRule}`)
      }
    }

    // 自定义校验器
    if (config.validator && this.validators.has(config.validator)) {
      try {
        const validator = this.validators.get(config.validator)
        const result = validator(value, config, sheetName)
        if (result && !result.valid) {
          return result
        }
      } catch (error) {
        return {
          valid: false,
          error: `自定义校验失败: ${error.message}`
        }
      }
    }

    return { valid: true }
  }

  /**
   * 创建工作表
   * @param {Array} data - 数据数组
   * @param {Object} sheetConfig - 工作表配置
   * @returns {Object} XLSX工作表对象
   */
  _createWorksheet(data, sheetConfig) {
    const headers = sheetConfig.columns.map(col => col.label)
    const sheetData = [headers]

    // 添加数据行
    for (const row of data) {
      const rowData = sheetConfig.columns.map(col => {
        const value = row[col.field]
        return this._formatExportValue(value, col.dataType)
      })
      sheetData.push(rowData)
    }

    const worksheet = XLSX.utils.aoa_to_sheet(sheetData)
    
    // 设置列宽
    if (sheetConfig.columns) {
      worksheet['!cols'] = sheetConfig.columns.map(col => ({
        width: col.width || 15
      }))
    }

    return worksheet
  }

  /**
   * 创建模板工作表
   * @param {Object} sheetConfig - 工作表配置
   * @returns {Object} XLSX工作表对象
   */
  _createTemplateWorksheet(sheetConfig) {
    const headers = sheetConfig.columns.map(col => col.label)
    const sheetData = [headers]

    // 添加示例数据行
    if (sheetConfig.examples && sheetConfig.examples.length > 0) {
      for (const example of sheetConfig.examples) {
        const rowData = sheetConfig.columns.map(col => example[col.field] || '')
        sheetData.push(rowData)
      }
    }

    const worksheet = XLSX.utils.aoa_to_sheet(sheetData)
    
    // 设置列宽
    worksheet['!cols'] = sheetConfig.columns.map(col => ({
      width: col.width || 15
    }))

    // 添加数据验证和样式
    if (sheetConfig.validations) {
      // 这里可以添加Excel数据验证规则
      // 由于XLSX库的限制，复杂的验证可能需要其他库支持
    }

    return worksheet
  }

  /**
   * 格式化导出值
   * @param {any} value - 原始值
   * @param {string} dataType - 数据类型
   * @returns {any} 格式化后的值
   */
  _formatExportValue(value, dataType) {
    if (value === null || value === undefined) return ''

    switch (dataType) {
      case 'date':
        if (value instanceof Date) {
          return value.toLocaleDateString()
        }
        return value
      
      case 'boolean':
        return value ? '是' : '否'
      
      default:
        return value
    }
  }
}

// 创建默认实例
export const excelProcessor = new ExcelProcessor()

// 注册常用校验器
excelProcessor.registerValidator('workOrderId', (value) => {
  if (value && !/^W-\d+$/.test(value)) {
    return {
      valid: false,
      error: '工单编号格式应为：W-数字'
    }
  }
  return { valid: true }
})

excelProcessor.registerValidator('productId', (value) => {
  if (value && !/^P-\d+$/.test(value)) {
    return {
      valid: false,
      error: '产品编号格式应为：P-数字'
    }
  }
  return { valid: true }
})

export default ExcelProcessor






